﻿#include "time_value.h"
#include <chrono>
#include <sstream>
#include <iomanip>
#ifdef _WIN32
#else
#include <cstring>
#endif

const TimeValue TimeValue::ZERO;

const int TimeValue::USECS = 1000000;
const int TimeValue::SECOND = 1;
const int TimeValue::MINUTE = 60;
const int TimeValue::HOUR = 60 * TimeValue::MINUTE;
const int TimeValue::DAY = 24 * TimeValue::HOUR;
const int TimeValue::WEEK = 7 * TimeValue::DAY;

#ifdef _WIN32
#define localtime(t,st) localtime_s(t,st)
#else
#define localtime(t,st) localtime_r(st,t)
#define sscanf_s sscanf
#endif

using namespace std::chrono;
TimeValue::TimeValue()
{
	tv_ = GetMsTime();
}


TimeValue::TimeValue(std::time_t msTime)
{
	tv_ = msTime;
}

TimeValue::~TimeValue()
{
}

std::time_t TimeValue::GetTime()
{
	auto tp = time_point_cast<seconds>(system_clock::now());
	auto tmp = duration_cast<seconds>(tp.time_since_epoch());
	return tmp.count() + g_timeOffSet;
}

std::time_t TimeValue::GetMsTime()
{
	auto time_now = system_clock::now();
	auto duration_in_ms = duration_cast<milliseconds>(time_now.time_since_epoch());
	return duration_in_ms.count() + g_timeOffSet * 1000;
}

std::string TimeValue::GetCurTimeStr(const char *normatStr)
{
	auto t = GetTime();
	tm time;
	localtime(&time, &t);
	std::stringstream ss;
	ss << std::put_time(&time, normatStr);
	return ss.str();
}

std::string TimeValue::GetCurTimeMsStr(const char *normatStr /*= "%Y-%m-%d %H:%M:%S"*/)
{
	auto mstime = GetMsTime();
	auto t = mstime / 1000;
	std::string str = GetCurTimeStr(normatStr);
	str += "." + std::to_string(mstime - t * 1000);
	return str;
}

void TimeValue::ParseTime(const char *str, std::time_t &time)
{
	auto t = GetTime();
	tm ltm;
	localtime(&ltm, &t);
	sscanf_s(str, "%4d-%2d-%2d %2d:%2d:%2d", &ltm.tm_year, &ltm.tm_mon, &ltm.tm_mday, &ltm.tm_hour, &ltm.tm_min, &ltm.tm_sec);
	ltm.tm_year -= 1900;
	ltm.tm_mon--;
	ltm.tm_isdst = -1;
	time = mktime(&ltm);
}

void TimeValue::ParseTime(const char *str, unsigned int &time)
{
	auto t = GetTime();
	tm ltm;
	localtime(&ltm, &t);
	sscanf_s(str, "%4d-%2d-%2d %2d:%2d:%2d", &ltm.tm_year, &ltm.tm_mon, &ltm.tm_mday, &ltm.tm_hour, &ltm.tm_min, &ltm.tm_sec);
	ltm.tm_year -= 1900;
	ltm.tm_mon--;
	ltm.tm_isdst = -1;
	time = mktime(&ltm);
}

std::time_t TimeValue::GetZeroTime(std::time_t srcTime)
{
	tm time;
	localtime(&time, &srcTime);
	time.tm_sec = 0;
	time.tm_min = 0;
	return mktime(&time);
}

std::time_t TimeValue::GetTodayZero()
{
	return GetZeroTime(GetTime());
}

bool TimeValue::IsSameDay(std::time_t l, std::time_t r)
{
	tm timeinfo1, timeinfo2;
	localtime(&timeinfo1, &l);
	localtime(&timeinfo2, &r);
	return (timeinfo1.tm_year == timeinfo2.tm_year) &&
		(timeinfo1.tm_mon == timeinfo2.tm_mon) &&
		(timeinfo1.tm_mday == timeinfo2.tm_mday);
}

bool TimeValue::IsSameWeek(std::time_t l, std::time_t r, int offsetSec /*= 0*/)
{
	return GetWeekStart(l, offsetSec) == GetWeekStart(r, offsetSec);
}

bool TimeValue::IsSameMonth(std::time_t l, std::time_t r, int offsetSec)
{
	return GetMonthStart(l, offsetSec) == GetMonthStart(r, offsetSec);
}

bool TimeValue::ExceedInterval(std::time_t target, int interval)
{
	return GetMsTime() - target >= interval;
}

int TimeValue::GetDay(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_mday;
}

int TimeValue::GetMonth(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_mon;
}

int TimeValue::GetYear(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_year;
}

int TimeValue::GetWeek(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_wday;
}

int TimeValue::GetHour(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_hour;
}

int TimeValue::GetMin(std::time_t time)
{
	tm t;
	localtime(&t, &time);
	return t.tm_min;
}

bool TimeValue::IsBetween(int beginHour, int beginMin, int endHour, int endMin, std::time_t curTime)
{
	std::time_t dayElapse = curTime - GetDayStart(curTime);
	return (dayElapse >= (beginHour * 60 * 60 + beginMin * 60) && dayElapse <= (endHour * 60 * 60 + endMin * 60));
}

bool TimeValue::IsCurMonth(int year, int month, int offsetSec)
{
	std::time_t curSec = GetTime();
	curSec -= offsetSec;
	return year == GetYear(curSec) && month == GetMonth(curSec);
}

std::time_t TimeValue::GetDayStart(std::time_t time, int offsetSec /*= 0*/)
{
	tm t;
	std::time_t newTime = time - offsetSec;
	localtime(&t, &newTime);
	return time - (t.tm_hour * 60 + t.tm_min) * 60 - t.tm_sec;//直接计算比使用mktime函数效率更高
}

time_t TimeValue::GetDayStart(int year, int month, int day)
{
	if (year < 1970 || month < 1 || month > 12 || day > 31)
		return 0;

	tm t;
	memset(&t, 0, sizeof(t));
	t.tm_year = year - 1900;
	t.tm_mon = month - 1;
	t.tm_mday = day;
	return mktime(&t);
}

std::time_t TimeValue::GetWeekStart(std::time_t time, int offsetSec)
{
	tm t;
	std::time_t newTime = time - offsetSec;
	localtime(&t, &newTime);
	return newTime - ((((t.tm_wday + 6) % 7) * 24 + t.tm_hour) * 60 + t.tm_min) * 60 - t.tm_sec;
}

std::time_t TimeValue::GetMonthStart(std::time_t time, int offsetSec)
{
	tm t;
	std::time_t newTime = time - offsetSec;
	localtime(&t, &newTime);
	return newTime - (((t.tm_mday - 1) * 24 + t.tm_hour) * 60 + t.tm_min) * 60 - t.tm_sec;
}

std::time_t TimeValue::GetMinuteStart(std::time_t time, int offsetSec /*= 0*/)
{
	tm t;
	std::time_t newTime = time - offsetSec;
	localtime(&t, &newTime);
	return time - t.tm_sec;
}

bool TimeValue::IsLeapYear(int year)
{
	return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

int TimeValue::GetDiffDay(std::time_t t1, std::time_t t2, int offsetSec /*= 0*/)
{
	std::time_t d1 = GetDayStart(t1, offsetSec);
	std::time_t d2 = GetDayStart(t2, offsetSec);
	return (d1 - d2) / (24 * 3600);
}

bool operator > (const TimeValue &tv1, const TimeValue &tv2) {
	if (tv1.sec() > tv2.sec())
		return 1;
	else if (tv1.sec() == tv2.sec() && tv1.usec() > tv2.usec())
		return 1;
	else
		return 0;
}

bool operator < (const TimeValue &tv1, const TimeValue &tv2) {
	return tv2 > tv1;
}

bool operator >= (const TimeValue &tv1, const TimeValue &tv2) {
	if (tv1.sec() > tv2.sec())
		return 1;
	else if (tv1.sec() == tv2.sec() && tv1.usec() >= tv2.usec())
		return 1;
	else
		return 0;
}

bool operator <= (const TimeValue &tv1, const TimeValue &tv2) {
	return tv2 >= tv1;
}

TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2) {
	TimeValue delta(tv1);
	delta -= tv2;

	return delta;
}

TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2) {
	TimeValue sum(tv1);
	sum += tv2;

	return sum;
}

TimeValue &TimeValue::operator -= (const TimeValue &tv) {
	this->set(this->sec() - tv.sec(), this->usec() - tv.usec());
	return *this;
}

TimeValue &TimeValue::operator += (const TimeValue &tv) {
	this->set(this->sec() + tv.sec(), this->usec() + tv.usec());
	return *this;
}

bool operator == (const TimeValue &tv1, const TimeValue &tv2) {
	return tv1.sec() == tv2.sec() && tv1.usec() == tv2.usec();
}

bool operator != (const TimeValue &tv1, const TimeValue &tv2) {
	return !(tv1 == tv2);
}

bool TimeValue::IsTimeout(std::time_t timeStamp) const
{
	return timeStamp * 1000 > tv_;
}

bool TimeValue::IsTimeout(const TimeValue &t) const
{
	return t > *this;
}

bool TimeValue::timeup(std::time_t t, int interval)
{
	if (t > tv_)
	{
		tv_ = TimeValue::GetMsTime() + interval;
		return true;
	}
	return false;
}
